﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text.RegularExpressions;

public class PreprocessSceneFile : Editor
{

    static readonly string unityMeshInsideGUID = "0000000000000000e000000000000000";
    static readonly string unityDefaultCubeFileId = "10202";
    static readonly string unityDefaultCapsuleFileId = "10208";
    static readonly string unityDefaultCylinderFileId = "10206";
    static readonly string unityDefaultSphereFileId = "10207";
    static readonly string unityPlaneFileId = "10209";
    static readonly string unityQuadFileId = "10210";
    static readonly string unityDefaultResource = "/unity default resources";

    [MenuItem("Tool/Preprocess Scene File")]
    public static void Process()
    {
        string path = Application.dataPath + "/" + "Scenes/WorldMap.unity";

        TextReader reader = File.OpenText(path);
        string content = reader.ReadToEnd();

        string result = string.Empty;

        //处理MonoBehaviour
        while (true)
        {
            int index = content.IndexOf("m_Script:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();
            int skipLength = line.Length + 1; //apply the "\n"

            int guidPlace = line.IndexOf("guid:");
            Debug.Assert(guidPlace != -1);
            string temp = line.Substring(guidPlace);
            string guid = temp.Split(',')[0].Split(':')[1].Trim();
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            string scriptName = Path.GetFileName(assetPath);
            line = line.Replace(guid, scriptName);

            result += line;
            result += "\n";

            //another 2 lines
            for (int i = 0; i < 2; ++i)
            {
                line = strReader.ReadLine();
                result += line;
                result += "\n";
                skipLength += line.Length + 1;
            }

            //check if there is addtional information for this monobaviour
            line = strReader.ReadLine();
            skipLength += line.Length + 1;

			while (!line.Contains("--- !u!") && line != null)
            {
                if (line.Contains("guid: "))
                {
                    guid = line.Split(',')[1].Split(':')[1].Trim();
                    assetPath = AssetDatabase.GUIDToAssetPath(guid);
                    assetPath = assetPath.Remove(0, "Assets/".Length);
                    line = line.Replace(guid, assetPath);
                }

                result += line;
                result += "\n";

				line = strReader.ReadLine ();
				skipLength += line.Length + 1;
            }

			result += line;
			result += "\n";

			content = content.Substring(index + skipLength);
        }

        result += content;

        //处理MeshRenderer
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_Materials:");
            if (index == -1)
                break;

            //
            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_Materials:"
            result += line;
            result += "\n";

            int skipLength = line.Length + 1;
            //line = strReader.ReadLine();
            while (true)
            {
                line = strReader.ReadLine();
                skipLength += line.Length + 1;
                if (!line.Contains("- {fileID:"))
                    break;

                line = line.Replace("- {fileID:", "- material: {fileID:");

                int guidPlace = line.IndexOf("guid:");
				if (guidPlace == -1) { //only "- {fileID : 0}"
					result += line;
					result += "\n";
					continue;
				}

                Debug.Assert(guidPlace != -1);
                string temp = line.Substring(guidPlace);
                string guid = temp.Split(',')[0].Split(':')[1].Trim();
                Debug.Log("Find a material guid:" + guid);
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                if (assetPath.Contains("Resources/"))
                {
                    int pos = assetPath.IndexOf("Resources/");
                    string matPath = assetPath.Substring(pos);
                    line = line.Replace(guid, matPath);
                }
                else
                {
                    Debug.LogError(string.Format("Material: {0} must move to a Resources folder.", assetPath));
                }

                result += line;
                result += "\n";
            }

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理MeshFilter
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_Mesh:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();
            int lineLength = line.Length + 1; //apply the "\n"
            if (line.Contains("guid:"))
            {
                int guidPlace = line.IndexOf("guid:");
                Debug.Assert(guidPlace != -1);
                string temp = line.Substring(guidPlace);
                string guid = temp.Split(',')[0].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                assetPath = assetPath.Remove(0, 7); //"Assets\"
                string fileId = line.Split(',')[0].Split(':')[2].Trim(); //fileID
                Debug.Log("MeshFilter's fileId: " + fileId);
                string fileIdToName = string.Empty;
                if (guid == unityMeshInsideGUID) //处理那些默认的资源
                {
                    fileIdToName = ConvertUnityDefaultMeshName(fileId);
                }
                else
                {
                    string metaPath = Application.dataPath + "/" + assetPath + ".meta";
                    fileIdToName = GetMeshNameInAsset(metaPath, fileId);
                }

                line = line.Replace(guid, assetPath);
                line = line.Replace(fileId, fileIdToName);
            }

            result += line;
            result += "\n";

            content = content.Substring(index + lineLength);
        }

        result += content;

		//处理Transform里的m_Children:
		content = result;
		result = string.Empty;

		while (true)
		{
			int index = content.IndexOf("m_Children:");
			if (index == -1)
				break;

			result += content.Substring(0, index);

			StringReader strReader = new StringReader(content.Substring(index));
			string line = strReader.ReadLine();  //"m_Children:"

			int skipLength = line.Length + 1;

			if (line.Contains ("[]")) {
				line = line.Replace ("[]", string.Empty);
				result += line;
				result += "\n";

				line = "  - {fileID: dummy}";
				result += line;
				result += "\n";
			}

			content = content.Substring(index + skipLength);
		}

		result += content;

        //处理prefab: m_Modifications
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_Modifications:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_Modifications:"
            result += line;
            result += "\n";

            int skipLength = line.Length + 1;

            while (true)
            {
                line = strReader.ReadLine();
                skipLength += line.Length + 1;
                if (!line.Contains("- target: {fileID:"))
                    break;

                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                assetPath = assetPath.Replace("Assets/", "");
                line = line.Replace(guid, assetPath);

                result += line;
                result += "\n";

                // read addtional 3 lines
                line = strReader.ReadLine();
                result += line;
                result += "\n";
                skipLength += line.Length + 1;

                line = strReader.ReadLine();
                result += line;
                result += "\n";
                skipLength += line.Length + 1;

                line = strReader.ReadLine();
                result += line;
                result += "\n";
                skipLength += line.Length + 1;
            }

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理prefab: m_ParentPrefab
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_ParentPrefab:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_ParentPrefab:"
            int skipLength = line.Length + 1;

            string guid = line.Split(',')[1].Split(':')[1].Trim();
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            assetPath = assetPath.Replace("Assets/", "");
            line = line.Replace(guid, assetPath);

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理prefab: m_RemovedComponents
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_RemovedComponents:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_RemovedComponents:"

            int skipLength = line.Length + 1;

            if (line.Contains("[]"))
            {
                //Add a dummy line here since I don't know yamldotnet can deal with this
                line = line.Replace("[]", string.Empty);
                result += line;
                result += "\n";

                //dummy
                line = line.Replace("m_RemovedComponents: ", "    - Component: {fileID: Dummy, guid: dummy, type: 2}");
                result += line;
                result += "\n";
            }
            else
            {
                result += line;
                result += "\n";
            }


            while (true)
            {
                line = strReader.ReadLine();
                skipLength += line.Length + 1;
                if (!line.Contains("- {fileID:"))
                    break;

                string fileID = line.Split(',')[0].Split(':')[1].Trim();
                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid).Remove(0, "Assets/".Length);
                assetPath = Application.dataPath + "/" + assetPath;
                string componentName = FindComponentName(assetPath, fileID);

                line = line.Replace(fileID, componentName);
                line = line.Replace("- {fileID:", "- Component: {fileID:");

                result += line;
                result += "\n";
            }

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理prefab: m_Mesh
        content = result;
        result = string.Empty;

        while (true)
        {
            //TODO: can be optimized (use m_Materials.Array.data as example
            int index = content.IndexOf("- target: {fileID:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"- target: {fileID:"

            string fileID = line.Split(',')[0].Split(':')[2].Trim(); // record the fileID
            string resourcePath = line.Split(',')[1].Split(':')[1].Trim(); // record the filePath

            result += line;
            result += "\n";
            int skipLength = line.Length + 1;

            if (!line.Contains("}"))
            {
                line = strReader.ReadLine();
                result += line;
                result += "\n";
                skipLength += line.Length + 1;
            }

            line = strReader.ReadLine();
            result += line;
            result += "\n";
            skipLength += line.Length + 1;

            Debug.Assert(line.Contains("propertyPath:"));
            string name = line.Split(':')[1].Trim();
            if (name == "m_Mesh")
            {
                line = strReader.ReadLine(); // jump line of "value:"
                result += line;
                result += "\n";
                skipLength += line.Length + 1;

                line = strReader.ReadLine();
                skipLength += line.Length + 1;

                Debug.Assert(line.Contains("objectReference:"));

                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string refFileID = line.Split(',')[0].Split(':')[2].Trim();
                string targetId = string.Empty;
                string targetPath = string.Empty;
                if (guid == unityMeshInsideGUID)
                {
                    targetId = ConvertUnityDefaultMeshName(refFileID);
                    targetPath = unityDefaultResource;
                }
                else
                {
                    string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                    assetPath = assetPath.Remove(0, 7);
                    targetPath = assetPath;
                    string metaPath = Application.dataPath + "/" + assetPath + ".meta";
                    targetId = GetMeshNameInAsset(metaPath, refFileID);
                }
                line = line.Replace(refFileID, targetId);
                line = line.Replace(guid, targetPath);

                result += line;
                result += "\n";

            }
            else
            {
                content = content.Substring(index + skipLength);
                continue;
            }

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理prefab: m_Materials.Array.data
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("propertyPath: m_Materials.Array.data");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"propertyPath: m_Materials.Array.data"

            result += line;
            result += "\n";
            int skipLength = line.Length + 1;

            line = strReader.ReadLine();
            Debug.Assert(line.Contains("value:"));
            result += line;
            result += "\n";
            skipLength += line.Length + 1;

            line = strReader.ReadLine();
            skipLength += line.Length + 1;
            Debug.Assert(line.Contains("objectReference:"));

            string guid = line.Split(',')[1].Split(':')[1].Trim();
            string assetPath = AssetDatabase.GUIDToAssetPath(guid);
            if (assetPath.Contains("Resources/"))
            {
                int pos = assetPath.IndexOf("Resources/");
                string matPath = assetPath.Substring(pos);
                line = line.Replace(guid, matPath);
            }
            else
            {
                Debug.LogError(string.Format("Material: {0} must move to a Resources folder.", assetPath));
            }

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理Animation: m_Animation
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_Animation:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_Animation:"

            int skipLength = line.Length + 1;

            if (line.Contains("guid"))
            {
                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                assetPath = assetPath.Remove(0, "Assets/".Length);
                line = line.Replace(guid, assetPath);
            }

            result += line;
            result += "\n"; //end of m_Animation line

            line = strReader.ReadLine();
            Debug.Assert(line.Contains("m_Animations:"));
            skipLength += line.Length + 1;

            if (line.Contains("[]"))
            {
                //Add a dummy line here since I don't know yamldotnet can deal with this
                line = line.Replace("[]", string.Empty);
                result += line;
                result += "\n";

                //dummy
                line = "  - clip: {fileID: Dummy, guid: dummy, type: 2}";
                result += line;
                result += "\n";
            }
            else
            {
                result += line;
                result += "\n";
            }


            while (true)
            {
                line = strReader.ReadLine();
                skipLength += line.Length + 1;
                if (!line.Contains("- {fileID:"))
                    break;

                line = line.Replace("- {fileID:", "- clip: {fileID:");

                if (line.Contains("guid"))
                {
                    string guid = line.Split(',')[1].Split(':')[1].Trim();
                    string assetPath = AssetDatabase.GUIDToAssetPath(guid).Remove(0, "Assets/".Length);
                    line = line.Replace(guid, assetPath);
                }

                result += line;
                result += "\n";
            }

            result += line;
            result += "\n";

            content = content.Substring(index + skipLength);
        }

        result += content;

        //处理Animator: m_Avatar, m_Controller
        content = result;
        result = string.Empty;

        while (true)
        {
            int index = content.IndexOf("m_Avatar:");
            if (index == -1)
                break;

            result += content.Substring(0, index);

            StringReader strReader = new StringReader(content.Substring(index));
            string line = strReader.ReadLine();  //"m_Avatar:"

            int skipLength = line.Length + 1;

            if (line.Contains("guid"))
            {
                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                assetPath = assetPath.Remove(0, "Assets/".Length);
                line = line.Replace(guid, assetPath);
            }

            result += line;
            result += "\n"; //end of m_Avatar line

            line = strReader.ReadLine();
            Debug.Assert(line.Contains("m_Controller:"));
            skipLength += line.Length + 1;

            if (line.Contains("guid"))
            {
                string guid = line.Split(',')[1].Split(':')[1].Trim();
                string assetPath = AssetDatabase.GUIDToAssetPath(guid);
                assetPath = assetPath.Remove(0, "Assets/".Length);
                line = line.Replace(guid, assetPath);
            }

            result += line;
            result += "\n";  //end of m_Controller

            content = content.Substring(index + skipLength);
        }

        result += content;

        //写成新的文件
        TextWriter writer = File.CreateText(path + ".txt");
        writer.Write(result);
        writer.Close();
    }

    static string FindComponentName(string file, string id)
    {
        TextReader reader = File.OpenText(file);
        string content = reader.ReadToEnd();

        string name = string.Empty;

        StringReader sr = new StringReader(content);

        while (true)
        {
            string line = sr.ReadLine();

            if (line == null)
                break;

            if (!line.Contains("--- !u!"))
                continue;

            string ident = line.Split('&')[1].Trim();
            if (ident != id)
                continue;

            line = sr.ReadLine();
            name = line.Split(':')[0];
            break;
        }

        reader.Close();

        return name;
    }

    static string ConvertUnityDefaultMeshName(string fileId)
    {
        string fileIdToName = null;

        if (fileId == unityDefaultCubeFileId)
        {
            fileIdToName = "_UnityCube_";
        }
        else if (fileId == unityDefaultCapsuleFileId)
        {
            fileIdToName = "_UnityCapsule_";
        }
        else if (fileId == unityDefaultCylinderFileId)
        {
            fileIdToName = "_UnityCylinder_";
        }
        else if (fileId == unityDefaultSphereFileId)
        {
            fileIdToName = "_UnitySphere_";
        }
        else if (fileId == unityPlaneFileId)
        {
            fileIdToName = "_UnityPlane_";
        }
        else if (fileId == unityQuadFileId)
        {
            fileIdToName = "_UnityQuad_";
        }

        return fileIdToName;
    }

    static string GetMeshNameInAsset(string file, string fileId)
    {
        TextReader tr = File.OpenText(file);
        string cont = tr.ReadToEnd();
        StringReader sr = new StringReader(cont);
        string l = sr.ReadLine();
        while (!l.Contains(fileId) && l != null)
        {
            l = sr.ReadLine();
        }

        Debug.Assert(l != null);

        string fileIdToName = l.Split(':')[1].Remove(0, 1); //remove a space ahead

        tr.Close();

        return fileIdToName;
    }
}
